The aim of this research is to analyse the FX data offerings from LSEG – the Blended Rate (TRB), FXAll Pricestream data (FXV) and our contributor data (Super RIC). These data sets have differing methodologies and sources to accommodate for a wide range of use cases and accurately reflect the different market tiers that exist in Foreign Exchange. This means that the LSEG data offering can provide a bespoke fit to our clients’ specific requirements and the markets they operate in to maximise accuracy.
While the Super RIC generally reflects the overall market price with indicative pricing and will serve the needs of most market participants, such as a trader eyeballing the market, the Blended Rate and Pricestream data offers pricing derived from real market activity and offers tick level granularity. These feeds reflect the most accurate price in the market and react instantly in highly volatile periods. This will be important as an input for client pricing calculation, high frequency traders and other market participants who are interested in high frequency price updates both for liquid and illiquid currency pairs.
We will use various metrics, such as mid-price, spreads, and realized variance to compare the data sets and show the strength of the Refinitiv FX data offering during specific times of high volatility. This research will show the users of this data how each data set reacts to a particular market move as well as the picture of the market that each data set displays.
The Article comprises of four main sections. In section 1, we will discuss the differences between Refinitiv FX data venues. Further, we will introduce tick data ingestion and aggregation process for all markets using Refinitiv's latest RD Library API. Section 3 will describe a FX market comparison use-case with a developed market currency, such as EUR and GBP. Finally, we will explore TRB, FXV and Super RIC market movements in emerging markets currencies, such as ZAR and SGD. In this analysis we will show how the Blended Rate and Pricestream data help to avoid the lags during sudden price movements and offer a noiseless pricing feed.
The Super RIC is the last price attributed to a specific contributor from a pool of freely available indicative bank/broker contributors that have provided Refinitiv with permission to display their pricing. The Super RIC is updated in real time with the last indicative quote price attributed to the specific contributor. Since contributions technology is used, even though it is updated in real-time, the rates might be 100s of milliseconds old by the time it reaches our aggregation system. Pricing is provided on a best endeavours basis using our real time quality algorithms to remove spikes and outliers from contributors, this is not a firm price. The Super RIC will not show major tier 1 bank pricing if they have not given permission to Refinitiv to attribute their pricing.
The TRB is the single most comprehensive source of indicative market rates, leveraging the 446bn per day trading volume on Refinitiv venues – ‘Matching’, our tier 1 bank to bank trading venue, and ‘FX All’, the market leading execution and workflow solution for corporate and institutional clients. The composite data is derived from firm orders with no last look pricing – meaning the price data is a truer reflection of the current market. Also included in the blend is indicative data from over 100 banks and interdealer brokers, weighted by importance. The rate covers 64 currency pairs and 4 precious metals. TRB updates in real-time whenever one of the underlying sources updates. Average updates are 500ms across 24 hours, but more like 4-5 per second in busy times and 1 per second in quiet times. It takes an FXall rate every 1 second, and a Matching rate up to every 200ms, plus whenever specific bank and broker contributors update their rates. The mid represents market consensus since it sources from Matching, FXall and trusted bank and Broker.
In addition to the above, Refinitiv also provide =FXV (FXall Price Stream) which is a volume-tiered FX Spot Market reference rates blended from rates of the platform’s top liquidity providers. FXV covers 75+ liquid pairs and aggregates multiple liquidity providers derived from the world’s largest liquidity pool. The FXV updates every 50 milliseconds. Volumes tiers are usually 1M, 5M, 10M base currency quote sizes, except for Metals and a few other non-USD based pairs. This data set also has a higher quote precision – e.g., 5 full decimals for EUR/USD. 3 Regional versions are available if low-latency collection of data is needed =FXVE, =FXVN, =FXVA.

To acquire tick data for FX we will be using Refinitiv Data(RD) Libraries API. To use the API we first need to configure refinitiv-data.config.json file located in a Configuraion folder depending on the access channel and connection parameters that needed to connect to the Refinitiv Data Platform. In the scope of this article we will be connected through a desktop session for which an app-key is required. More on the configuration of RD libraries can be found here.
import os
os.environ["RD_LIB_CONFIG_PATH"] = "Configuration"
To start, we first install and import the necessary packages.The code are built using Python 3.9. Other prerequisite packages are installed and imported below:
# !pip install refinitiv.data
# !pip install pandas
# !pip install numpy
# !pip install plotly
import refinitiv.data as rd
from refinitiv.data.content import historical_pricing
from refinitiv.data.content import news
import datetime
from datetime import datetime
from dateutil import parser
import pandas as pd
import numpy as np
import re
import functools as ft
import plotly.express as px
from pathlib import Path
import plotly.io as pio
After we install and import the required modules we open an RD desktop session to ingest the FX data.
rd.open_session()
<refinitiv.data.session.Definition object at 0x13fe01700 {name='workspace'}>
Before processing to the fx data ingestion, it should be noted, that currently RD Libraries API provides access to the last 3 month of the tick data, thus all the economic events impacted the fx price and discussed in this article are from the last 3 month. Another limitation of the API is that a single request populates maximum of 10000 rows where the total number of tick data for a day can reach more than a million. Thus, we request the data under a loop by getting and requesting from the latest tick time. The request is wrapped by a try catch statement to avoid data loss if any network error happens during our request.
To ingest FX data, we have built a class with a set of function allowing us not only to request the data from the RD libraries APIs but also conduct several operations to include concatenation and type casting. The ObtainingFXData class comprises of the following functions:
class ObtainingFXData:
def __init__(self, fx, start_date, end_date):
self.fx = [fx]
self.start_date = parser.parse(start_date).replace(tzinfo=None)
self.end_date = parser.parse(end_date).replace(tzinfo=None)
def get_FX_data(self):
print(f'Requesting tick data for {self.fx[0]} for the period {self.start_date} to {self.end_date}')
response_df = self.__request_data()
self.__save_csv(self.__change_types(response_df))
print(f'{response_df.shape[0]} datapoints for {self.fx[0]} are created and stored')
return response_df
def __request_data(self):
response_df = pd.DataFrame()
while self.end_date >= self.start_date:
try:
df = rd.get_history(universe = self.fx, end = self.end_date, count = 10000, fields = ["BID","ASK","MID_PRICE"],interval = 'tick')
self.end_date = self.__update_end_date(df)
response_df = self.__concat_dfs(response_df, df)
except:
continue
return response_df
def __update_end_date(self, df):
self.end_date = df.index.min().replace(tzinfo=None).strftime('%Y/%m/%d %H:%M:%S.%f')
self.end_date = datetime.strptime(self.end_date,'%Y/%m/%d %H:%M:%S.%f')
return self.end_date
def __concat_dfs(self, response_df, df):
if len(response_df):
response_df = pd.concat([response_df, df], axis=0)
else:
response_df = df
return response_df
def __change_types(self, response_df):
response_df.reset_index(inplace = True)
response_df['Timestamp'] = pd.to_datetime(response_df['Timestamp'])
response_df['BID'] = pd.to_numeric(response_df['BID'])
response_df['ASK'] = pd.to_numeric(response_df['ASK'])
response_df['MID_PRICE'] = pd.to_numeric(response_df['MID_PRICE'])
return response_df
def __save_csv(self, response_df):
response_df.to_csv(f'{self.fx[0]}.csv')
To analyze the market movements and the volatility of FX markets and compare the metrics of TRB and the FXV with the Super RIC for different currencies we may have to zoom out and zoom into the tick data. For that we may need to aggregate the tick data into certain intervals and then show differences via plots. For that, we have created an object class called AggregatedDfWithMetrics which returns aggregated with a specified interval dataframe of the original dataframe containing tick values. To achieve this the class introduces the following functions:
class AggregatedDfWithMetrics:
def __init__(self, df):
self.df = self.__change_types(df)
def compute_metrics_and_aggregate(self, ric, interval, origin_time, end_time):
origin, end = self.__get_periods(origin_time, end_time)
filtered_df = self.__filter_by_origin(origin, end)
self.__add_spread_and_middiff(filtered_df)
count_df, max_vals_df, min_vals_df, var_df = self.__group_elements(filtered_df, interval, origin)
aggregated_df = filtered_df.groupby(pd.Grouper(key = 'Timestamp', freq = interval, origin = origin)).mean()
self.__calculate_and_add_metrics(aggregated_df, count_df, max_vals_df, min_vals_df, var_df)
return aggregated_df.add_suffix(f'_{ric}')
def __get_periods(self, origin_time, end_time):
date = self.df['Timestamp'].iloc[0].strftime("%Y-%m-%d")[:10]
origin = pd.to_datetime(f'{date} {origin_time}.370000+00:00')
end = pd.to_datetime(f'{date} {end_time}.370000+00:00')
return origin, end
def __filter_by_origin(self, origin, end):
self.df = self.df.loc[(self.df['Timestamp'] > origin) & (self.df['Timestamp'] < end)].sort_values(by = 'Timestamp')
return self.df
def __group_elements(self, filtered_df, interval, origin):
count_df = filtered_df.groupby(pd.Grouper(key = 'Timestamp', freq = interval, origin = origin)).count()
max_vals_df = filtered_df.groupby(pd.Grouper(key = 'Timestamp', freq = interval, origin = origin)).max()
min_vals_df = filtered_df.groupby(pd.Grouper(key = 'Timestamp', freq = interval, origin = origin)).min()
var_df = filtered_df.groupby(pd.Grouper(key = 'Timestamp', freq = interval, origin = origin)).var()
return count_df, max_vals_df, min_vals_df, var_df
def __add_spread_and_middiff(self, filtered_df):
filtered_df['SPREAD'] = filtered_df['ASK'] - filtered_df['BID']
filtered_df['diff_mid'] = filtered_df['MID_PRICE'].diff()
return filtered_df
def __calculate_and_add_metrics(self, aggregated_df, count_df, max_vals_df, min_vals_df, var_df):
aggregated_df['COUNT'] = count_df['MID_PRICE']
aggregated_df['MAX_SPREAD'] = max_vals_df['SPREAD']
aggregated_df['MIN_SPREAD'] = min_vals_df['SPREAD']
aggregated_df['RANGE_SPREAD'] = aggregated_df['MAX_SPREAD'] - aggregated_df['MIN_SPREAD']
aggregated_df['VAR_MID_DIFF'] = var_df['diff_mid']
return aggregated_df
def __change_types(self, df):
df.reset_index(inplace = True, drop = True)
df['BID'] = pd.to_numeric(df['BID'])
df['ASK'] = pd.to_numeric(df['ASK'])
df['MID_PRICE'] = pd.to_numeric(df['MID_PRICE'])
df['Timestamp'] = pd.to_datetime(df['Timestamp'])
return df
Given that developed and emerging market currencies may respond differently to the economic events in terms of accurate and non-latent reflection of the new information in the price, we will introduce cases for both currency markets. This will ensure robustness of comparison differences between TRB and the FXV with the Super RIC during times of high market movement and volatility.
In this section, we will compare TRB and the FXV with the Super RIC for developed market currencies, such as EUR and GBP and show the accuracy of the data during times of high market movement and volatility caused by the economic events.

For this case we will investigate how the abovementioned economic event impacted the different FX markets for EUR.
Now, let's request FX data for EUR for different FX markets, including Super RIC, TRB and FXVs (AS, BS, CS). Below we initialize RIC/rics, start and end datetime of the request as well as an empty dictionary where will store dataframes for each FX market.
RIC = 'EUR'
rics = [f'{RIC}=', f'{RIC}=TRB', f'{RIC}AS=FXV', f'{RIC}BS=FXV', f'{RIC}CS=FXV']
start = '2023-01-14T00:00:00Z'
end = '2023-01-14T23:59:00Z'
fx_dict = {}
Below, we first check whether we have the data already stored in our downloads folder or not. If not, we make an API call using Refinitiv RD Library.
for ric in rics:
df_name = ric.split('=')[0]+'_'+ric.split('=')[1]
path = Path(f'downloads/EUR_1401/{ric}.csv')
if path.is_file():
fx_dict[df_name] = pd.read_csv(f'downloads/EUR_1401/{ric}.csv', index_col=[0])
else:
fx_dict[df_name] = ObtainingFXData(ric, start, end).get_FX_data()
Next, we aggregate the tick data in 5 minute intervals to analyze the market movements and the volatility of different FX markets. For that, we intialize an empty dictionary and call compute_metrics_and_aggregate function from AggregatedDfWithMetrics class for each market and store aggregated dataframes in that dictionary.
Since we are dealing here with a highly liquid currency, we will aggregate our tick data in 1-minute intervals. Additionally, let us zoom into about +-10 minutes from the actual market movement.
fx_dict_interval = {}
for df, ric in zip(fx_dict, rics):
fx_dict_interval[df+'interval'] = AggregatedDfWithMetrics(fx_dict[df]).compute_metrics_and_aggregate(ric, '1min', '13:14:12', '13:35:33')
Now, let's illustrate line graphs for Mid Price, spread and realized variance, for which we have introduced a Plot object.
Finally, we plot some of the metrics for each market for comparative analysis. For that we have built a class named Plot which takes the dictionary of fx dataframes (with aggregated intervals), list of rics and metrics for initialization and plots comparison line graphs for each metric. The class comprises of the following private functions:
class Plot:
def __init__(self, df_dict, rics, metrics):
self.df_dict = df_dict
self.rics = rics
self.metrics = metrics
def plot_graph(self):
final_df = self.__merge_dfs_and_add_spread_diff()
for metric in self.metrics:
df_metric = self.__filter_df_by_metric(final_df, metric)
fig = px.line(df_metric, x=df_metric.index, y=df_metric.columns)
fig.update_layout(height=600, width=1000, legend=dict())
fig.show()
def __merge_dfs_and_add_spread_diff(self):
merged_df = pd.concat(self.df_dict.values(), axis=1, join="outer")
final_df = self.__calculate_spread_diffs(merged_df)
return final_df
def __filter_df_by_metric(self, final_df, metric):
return final_df.filter(regex=f'^{metric}')
def __calculate_spread_diffs(self, merged_df):
for ric in self.rics[1:]:
merged_df[f'spread_diff_{ric}_{rics[0]}'] = merged_df[f'SPREAD_{ric}'] - merged_df[f'SPREAD_{rics[0]}']
return merged_df
Below, we specify the metrics for which we want to show a plot and call plot_graph function from the Plot object.
metrics = ['MID_PRICE', 'SPREAD', 'VAR']
Plot(fx_dict_interval, rics, metrics).plot_graph()
By looking at the line plots above we observe the highest spread for the Super RIC and lowest for EURAS. Apart from the difference in the size of the spread, we observe that both TRB and FXV feeds respond better to the market event. Particularly the spreads for those pairs widen during the sudden price change and stabilizes back afterwards. Whereas the spread for the Super RIC remains stale during the observation period. When it comes to different FXV tiers and TRB, we observe wider spreads as volume tier in FXV increases. EUR=TRB responds to the event by widening the spread at 13:24:12. The spread for the latter is above EURAS=FXV due to the highest spread of EUR= (as it is sourced from the Super RIC as well).
This assertion is further evidenced by looking at the realized variance plot of different FX markets. The realized variance plot shows how realized variance of mid-price returns for Super RIC and TRY=TRB spike during the economic event suggesting that the event is reflected after a certain lag in those markets. The plot for Mid-price fails to highlight the lagged reflection of new information, again, perhaps, because of aggregation.
To see that, let us zoom into the event using tick level prices from about +- 15 second from the actual market movement.
Now, let's zoom into the time of the economic event and observe the mid prices and spreads in tick level. To filter our original tick level dataframes by the specified periods and add the comparison metrics an object class Filterdf is created. The class returns the filtered dataframe by utilizing the following functions:
class Filterdf:
def __init__(self):
self.RICs = [f'{RIC}=', f'{RIC}=TRB', f'{RIC}AS=FXV', f'{RIC}BS=FXV', f'{RIC}CS=FXV']
self.fitered_df = {}
def get_filtered_df(self, fx_dict, RIC, start_time, end_time):
for df, ric in zip(fx_dict, self.RICs):
self.fitered_df[df] = self.compute_and_add_metrics(fx_dict[df])
self.fitered_df[df] = self.add_name_suffix(self.fitered_df[df], ric)
self.fitered_df[df] = self.filter_df(self.fitered_df[df], start_time, end_time)
return self.fitered_df
def filter_df(self, fx_df, start_time, end_time):
date = str(fx_df.index[0])[:10]
fx_df = fx_df.loc[( pd.to_datetime(fx_df.index) > pd.to_datetime(f'{date} {start_time}.000000+00:00')) & ( pd.to_datetime(fx_df.index) < pd.to_datetime(f'{date} {end_time}.000000+00:00'))]
fx_df = fx_df.loc[~fx_df.index.duplicated(keep='first')].sort_values(by = 'Timestamp')
return fx_df
def compute_and_add_metrics(self, fx_df):
fx_df['SPREAD'] = fx_df['ASK']-fx_df['BID']
fx_df['MID_DIFF'] = fx_df['MID_PRICE'].diff()
fx_df['VAR'] = fx_df['MID_DIFF'].var()
return fx_df
def add_name_suffix(self, fx_df, ric):
fx_df['Timestamp'] = pd.to_datetime(fx_df['Timestamp'])
fx_df = fx_df.set_index('Timestamp')
fx_df.index = fx_df.index.astype('object')
fx_df = fx_df.add_suffix(f'_{ric}')
return fx_df
fx_dict = Filterdf().get_filtered_df(fx_dict, 'EUR', '13:24:00', '13:24:33')
metrics = ['MID_PRICE', 'SPREAD']
Plot(fx_dict, rics, metrics).plot_graph()
What we can see while looking at the first plot is the fastest response by all FXV feeds and lagged response to the market event by EUR=. Particularly, the FXVs had a steep decline at 13:24:14, whereas the Super RIC reflected the new market environment at 13:24:19 only. Furthermore, the mid-price for the Super RIC carries a lot of noise with many high up and down spikes capturing the actual market condition at 13:24:30. We also observe 1 second lagged response by EUR=TRB, however it could capture the market movement throughout the observation period.
We provide zoomed plot for the Spreads for EUR currency pairs as well. This shows the widening spread for FXVs with large spikes at the beginning of the event, whereas spreads for EUR= remains stale (carrying a lot of noise after the event) throughout the period.
Now, let us investigate another developed currency market - GBP- and observe if we see similar responses by different currency feeds there as well.

For this case we will investigate how report on US CPI moved GBP market, in this case upwards compared to the downward move in EUR. For that, let's initialize RIC/rics, start and end datetime of the requests and an empty dictionary to store requested dataframes.
RIC = 'GBP'
rics = [f'{RIC}=', f'{RIC}=TRB', f'{RIC}AS=FXV', f'{RIC}BS=FXV', f'{RIC}CS=FXV']
start = '2022-08-10T00:00:00Z'
end = '2022-08-10T23:59:00Z'
fx_dict = {}
Below, we first check whether we have the data already stored in our downloads folder or not. If not, we make an API call using Refinitiv RD Library.
for ric in rics:
df_name = ric.split('=')[0]+'_'+ric.split('=')[1]
path = Path(f'downloads/GBP_1008/{ric}.csv')
if path.is_file():
fx_dict[df_name] = pd.read_csv(f'downloads/GBP_1008/{ric}.csv', index_col=[0])
else:
fx_dict[df_name] = ObtainingFXData(ric, start, end).get_FX_data()
Here again, since we are dealing here with a highly liquid currency, we will aggregate our tick data in 1-minute intervals. Additionally, let us zoom into the event from about +-10 minutes from the actual market movement.
fx_dict_interval = {}
for df, ric in zip(fx_dict, rics):
fx_dict_interval[df+'interval'] = AggregatedDfWithMetrics(fx_dict[df]).compute_metrics_and_aggregate(ric, '1min', '12:18:47', '12:38:33')
Finally, let's call plot_graph function from the Plot object to illustrate line graphs for Mid Price, spread and realized variance.
metrics = ['MID_PRICE', 'SPREAD', 'VAR']
Plot(fx_dict_interval, rics, metrics).plot_graph()
The plots above show a similar picture we had for EUR with a couple of differences. Starting from the similarities, we can observe that all spreads widen at the start of the economic event, the largest volume tier FXV with the widest spreads. The difference with the EUR plot is that the mid price for the Super RIC for GBP, although weak, but responded the market event. Additionally spread for the Super RIC was lower than the FXVs during the event and bigger before and after.
As it comes to the realized variances, we experience similar patterns compared to the EUR variances. Particularly we observe the highest realized variance of mid-price returns for the super RIC and the lowest for GBPCS=FXV.
Overall, for GBP as well we observe FXVs reflect the market condition best, whereas the Super RIC experiences a lag in reflecting the actual market environment.
Finally, let us zoom into the event using tick level prices from about +- 15 seconds from the actual market movement to explore the potential lagged responses.
fx_dict = Filterdf().get_filtered_df(fx_dict, 'EUR', '12:29:45', '12:30:15')
metrics = ['MID_PRICE', 'SPREAD']
Plot(fx_dict, rics, metrics).plot_graph()
The Mid price plot for GBP markets show very similar picture to EUR markets. Particularly we observe 5 and 2 second lagged response by the Super RIC and GBP=TRB, respectively. Moreover, the Super RIC missed the market up and correction during 12:30:01 and 12:30:06 and followed the general market trend starting from 12:30:08.
This analysis of the different feeds of developed market currencies leads to the conclusion that FXVs best respond and reflect the sudden changing market condition. TRB reflects the market event with a couple of seconds lag, whereas the Super RIC offers much larger lag and sometimes misses the actual market environment during the periods of high volatility.
After discussing how different currency feeds from developed markets reflect the sudden price movements caused by economic events, in this section, we will compare TRB and the FXV with the Super RIC for emerging market currencies. Particularly we will investigate ZAR (South African Rand) and SGD (Singapore Dollar) and show how well different market feeds reflect the market conditions during the times of high market movement and volatility caused by the economic events.

Let us start the analysis of emerging market currencies from ZAR. ZAR, after a negative dip at around 13:30 recovered and closed 0.36% up amid news on a possible cooling of US CPI. In this study, we will delve into that negative move and will analyse how different currency market feeds responded to the day's volatility caused by the news. Now, let's request FX data for ZAR for different FX markets, including Super RIC, TRB and FXVs.
Below we initialize RIC/rics, start, and end datetime of the request as well as an empty dictionary where will store dataframes for each FX market.
RIC = 'ZAR'
start = '2022-11-15T00:00:00Z'
end = '2022-11-15T23:59:00Z'
rics = [f'{RIC}=', f'{RIC}=TRB', f'{RIC}AS=FXV', f'{RIC}BS=FXV', f'{RIC}CS=FXV']
fx_dict = {}
for ric in rics:
df_name = ric.split('=')[0]+'_'+ric.split('=')[1]
path = Path(f'downloads/ZAR_1511/{ric}.csv')
if path.is_file():
fx_dict[df_name] = pd.read_csv(f'downloads/ZAR_1511/{ric}.csv', index_col=[0])
else:
fx_dict[df_name] = ObtainingFXData(ric, start, end).get_FX_data()
Next, let us aggregate the tick data in 5-minute intervals to analyse the market movements and the volatility of different FX markets.
fx_dict_interval = {}
for df, ric in zip(fx_dict, rics):
fx_dict_interval[df+'interval'] = AggregatedDfWithMetrics(fx_dict[df]).compute_metrics_and_aggregate(ric, '5min', '12:00:00', '15:00:00')
metrics = ['MID_PRICE', 'SPREAD', 'VAR']
Plot(fx_dict_interval, rics, metrics).plot_graph()
The first plot showing mid-price movement in different FX markets shows the trendline of the price for the 15th of November. We observe a negative move at around 13:25 and bounce back after about 10 minutes. To measure how well each of the markets responded to this move let us investigate spread and realized variance graphs during that time.
From the Spread plots, we see that all the markets responded to the market event by widening the spreads, moreover the spreads are wider for FXVBC and FXVCS. Although the spreads of Super RIC also responded to the market move, the variance plot suggests much higher and unstable variance compared to the rest of the feeds, suggesting more noise in the Super RIC feed compared to TRB and FXV feeds.
Despite the noise, we could not identify a lag in 5-minute aggregation, so let us now zoom into the event using tick level prices.
Below, we initialize Filterdf class by requesting tick data from about +-1 minute from the time the event started to move the market.
fx_dict_filtered = Filterdf().get_filtered_df(fx_dict, 'ZAR', '13:29:30', '13:31:30')
metrics = ['MID_PRICE', 'SPREAD']
Plot(fx_dict_filtered, rics, metrics).plot_graph()
The zoomed in Mid price data confirms the noise in Super RIC and identifies about 5 second lag between 13:30:03 and 13:30:08. When it comes to the Spread plot, it shows the widening spreads for FXVs during the time of the economic event and stale behaviour from the Super RIC and TRB for the same period. So, here again, the FXV feeds captured the market environment best.
Finally, let us investigate another developed market currency - Singapore Dolar (SGD)- to see if can reveal more insights from the emerging market currency feeds.

SGD after a positive spike at noon closed 0.1% down amid a much-awaited U.S. inflation reading for cues on further rate hikes. In this case with SGD, we will analyse how different currency market feeds responded to the day's volatility caused by the news. Now, let us request FX data for SGD for different FX markets, including Super RIC, TRB and FXVs. Below we initialize RIC/rics, start and end datetime of the request as well as an empty dictionary where will store dataframes for each FX market.
RIC = 'SGD'
start = '2022-10-13T00:00:00Z'
end = '2022-10-13T23:59:00Z'
rics = [f'{RIC}=', f'{RIC}=TRB', f'{RIC}AS=FXV', f'{RIC}BS=FXV', f'{RIC}CS=FXV']
fx_dict = {}
for ric in rics:
df_name = ric.split('=')[0]+'_'+ric.split('=')[1]
path = Path(f'downloads/SGD_1310/{ric}.csv')
if path.is_file():
fx_dict[df_name] = pd.read_csv(f'downloads/SGD_1310/{ric}.csv', index_col=[0])
else:
fx_dict[df_name] = ObtainingFXData(ric, start, end).get_FX_data()
Next, let us aggregate the tick data in 5-minute intervals to analyse the market movements and the volatility of different FX markets.
fx_dict_interval = {}
for df, ric in zip(fx_dict, rics):
fx_dict_interval[df+'interval'] = AggregatedDfWithMetrics(fx_dict[df]).compute_metrics_and_aggregate(ric, '5min', '09:00:00', '16:00:00')
metrics = ['MID_PRICE', 'SPREAD', 'VAR']
Plot(fx_dict_interval, rics, metrics).plot_graph()
The first plot showing mid-price movement in different FX markets shows the trendline of the price for the 13th of October. We observe the impact of the economic event on the prices around 12:28 when the prices increased 0.5% during the following 40 minutes and decreased during the rest of the day, overall decreasing 0.1%. To measure how well each of the markets responded to this move let us investigate spread and realized variance graphs.
From the Spread plots, we see similar picture to EUR, where FXV and TRB feeds responded to the market event by widening the spreads, whereas the spread for the Super RIC remain stale and responded to the event with a lag. The latter is well seen in the Variance plot, where the realized variance for the Super RIC mid-price spiked about 8 times.
To confirm the lagged information response, let's zoom into the event using tick level prices as the plot for Mid-price above fails to highlight the lagged reflection of new information, perhaps, because of the 5-minute aggregation.
Below, we initialize Filterdf class by requesting tick data from about +-1 minute from the time the event started to move the market.
fx_dict_filtered = Filterdf().get_filtered_df(fx_dict, 'SGD', '12:29:00', '12:31:00')
Next, we call plot_graph function from the Plot object to illustrate line graphs for Mid Price and the spread.
metrics = ['MID_PRICE', 'SPREAD']
Plot(fx_dict_filtered, rics, metrics).plot_graph()
What we can observe from the Mid-Price plot is that Super RIC misses more than 400 ticks during the 20 seconds between 12:30:05 and 12:30:25, where the rest of the markets experience several ups and downs. The granularity offered here by FXV and TRB feeds can be an immense value for the high frequency traders and other market participants interested in fastest possible market price updates. It is worth also highlighting, that although the TRB copes with the market, it offers a little bit of a noise and latency compared to the FXVs.
We provide a zoomed plot for the Spreads as well, which shows the widening spreads for FXVs during the time of the economic event. Additionally, we can observe stale behaviour from the Super RIC and TRB. The latter is perhaps because TRB is mix from FXVAS and the Super RIC itself - the latency of which during highly volatile periods impacts the overall behaviour of the TRB as well.
We have demonstrated how one can analyse any FX pair using zoomed-out/aggregated data to show performance across longer timeframes – or using zoomed-in/tick data to show performance across very small timeframes. We have provided the code to conduct this efficiently for any relevant currency pair. We set about testing the reactions of both developed and emerging market currencies to economic or market events to see which FX feed source performed best.
In summary, we have shown that the Super RICs, formed from indicative prices, perform reasonably during normal market modes, accurately reflecting actual market conditions and introduces small lags in high volatile periods. It is worth mentioning here that the lagging would be more acute in credit-constrained currencies, such as TRY. In this market, not all local banks have credit with major western banks and consequently we observe a lag in price formation particularly in volatile markets.
Overall, the Super RIC despite some lag and noise, will obviously serve the needs of most of the market participants eyeballing the market. However, high frequency traders and other market participants who are interested in high frequency price updates will benefit more from FXV and TRB market feeds. These feeds are derived from real market activity and offer tick level granularity permitting the reflection of actual market conditions in the best possible way.